/*
 **********************************************************
 *
 * Programme :	liste.c
 *
 * ecrit par :	BAYRAMOV Matin & IBRAHIMLI Nihat
 *
 * resume 	: 	contient les fonctions utiles
 * 				pour gerer le menu de l'application
 *
 * date 	:   Mar 4, 2013
 *
 ***********************************************************
 */

#include "menu.h"
#include "parser.h"


int userChoice = 45;
Graphe * graph = NULL;

// Permet de créer et manipuler un graph.
void menuCreation() {

	userChoice = -1;

	printf("\nVeuillez saisir le nombre maximum de sommet : ");

	char c;

	if (scanf("%d%c", &userChoice, &c) != 2) {
		printf("Saisie est invalide !\n");
		menuRedirect(MENU_MAIN_MENU);
		return;
	}
	else if(userChoice <= 0) {
		printf("Saisie est negative ou null\n" );
	}
	else if (c != '\n' ) {
		printf("Extraneous input\n");
	}


	// Création de graph
	int res = creation(&graph, userChoice);

	if (res == GRAPHE_DEJA_EXISTANT) {
		printf("Attention le graph est existe déjà \n");
		menuRedirect(MENU_MAIN_MENU);
	}

	// Invalide max sommet
	if (res == MAX_SOMMET_INVALIDE) {
		printf("Attention le nombre maximum de sommet n'est pas valide !\n");
		menuCreation();
	}

	// Probeleme mémorie
	if (res == PROBLEME_MEMOIRE) {
		printf("Attention un problème de mémoire est apparut !\n");
		menuQuitter();
	}
}

// Permet de lire un graph depuis un fichier
int menuLecture() {

	char name [256];
	char * fileName = name;

	printf("Veuillez saisir le nom du fichier \navec l'extention (name.txt) : ");

	if (scanf("%s", fileName) > 0) {
	    printf("Ok. Nous chargeons votre fichier %s.\n", fileName);
	}
	else {
		printf("Attention - Vous avez saisi rien.\n");
		menuLecture();
	}

	menuFreeAllMemory();

	int res = fileLoading(fileName, &graph);


	if(res != RES_OK){
		printf("\nIl y une erreur dans le fichier indiqué !\n\n\n");
		menuQuitter();
	}

	return RES_OK;
}

// Arret le programe
void menuQuitter() {

	menuFreeAllMemory();

	exit(0);
}

// Permet d'aller à la menu principale
void menuMainMenu(char * fileName) {

	if (userChoice < 0) {
		return;
	}

	if (fileName != NULL) {
		int res = fileLoading(fileName, &graph);

		if(res != RES_OK){
			printf("\nIl y une erreur dans le fichier indiqué !\n\n\n");
			menuQuitter();
		} else {
			menuSecondMenu();
		}
	}

	printf("\tMENU\n\n");

	printf("%d :- creation manuelle\n", MENU_CREATION);
	printf("%d :- creation aleatoire\n", MENU_CREATION_ALEATOIRE);
	printf("%d :- lecture\n", MENU_LECTURE);
	printf("%d :- quitter\n", MENU_QUITTER);

	printf("\nVeuillez choisir une de ces operations : ");
	char c;

	if (scanf("%d%c", &userChoice, &c) != 2) {
		printf("Saisie est invalide !\n\n\n");
		menuQuitter();
	}
	else if(userChoice != MENU_CREATION
			&& userChoice != MENU_CREATION_ALEATOIRE
			&& userChoice != MENU_LECTURE
			&& userChoice != MENU_QUITTER) {
		printf("Choix est invalide !\n" );
		menuMainMenu(NULL);
	}
	else if (c != '\n' ) {
		printf("Extraneous input\n\n\n");
		menuQuitter();
	}

	menuRedirect(userChoice);
}

// Permet d'aller au deuxième menu
void menuSecondMenu() {

	if (userChoice < 0) {
		return;
	}

	printf("\n\n\tMENU\n\n");
	printf("%d :- menu principal\n", MENU_MAIN_MENU);
	printf("%d :- insertionSommet\n", MENU_INSERTION_SOMMET);
	printf("%d :- suppressionSommet\n", MENU_SUPPRESSION_SOMMET);
	printf("%d :- insertionArete\n", MENU_INSERTION_ARETE);
	printf("%d :- suppressionArete\n", MENU_SUPPRESSION_ARETE);
	printf("%d :- sauvegarder\n", MENU_SAUVEGARDER);
	printf("%d :- completer le graph\n", MENU_COMPLETE_GRAPH);
	printf("%d :- calcul exact TSP Solution\n", MENU_EXACT_TSP_SOLUTION);
	printf("%d :- calcul plus proche voisin\n", MENU_PLUS_PROCHE_VOISIN);
	printf("%d :- calcul plus petit detour\n", MENU_PLUS_PETIT_DETOUR);
	printf("%d :- calcul graph ARPM\n", MENU_CALCUL_GRAPH_ARPM);
	printf("%d :- heuristique de Christofides\n", MENU_CALCUL_CHRISTOFIDES);
	printf("%d :- afficher\n", MENU_AFFICHER);


	printf("\nVeuillez choisir une de ces operations : ");

	char c;
	userChoice = -1;

	if (scanf("%d%c", &userChoice, &c) != 2) {
		printf("Saisie est invalide !\n\n\n");
		menuQuitter();
	}

	if(userChoice != MENU_MAIN_MENU
			&& userChoice != MENU_INSERTION_SOMMET
			&& userChoice != MENU_SUPPRESSION_SOMMET
			&& userChoice != MENU_INSERTION_ARETE
			&& userChoice != MENU_SUPPRESSION_ARETE
			&& userChoice != MENU_SAUVEGARDER
			&& userChoice != MENU_COMPLETE_GRAPH
			&& userChoice != MENU_EXACT_TSP_SOLUTION
			&& userChoice != MENU_PLUS_PROCHE_VOISIN
			&& userChoice != MENU_PLUS_PETIT_DETOUR
			&& userChoice != MENU_CALCUL_GRAPH_ARPM
			&& userChoice != MENU_CALCUL_CHRISTOFIDES
			&& userChoice != MENU_AFFICHER) {

			printf("Choix est invalide !\n" );
			menuSecondMenu();
	}else if (c != '\n' ) {
		printf("Extraneous input\n\n\n");
		menuQuitter();
	}

	menuRedirect(userChoice);

}

// Permet de sauvegarder un graph
int menuSauvegarder() {

	char name [256];
	char * fileName = name;

	printf("Veuillez saisir le nom du fichier \navec l'extention (name.txt, ..: ");

	if (scanf("%s", fileName) > 0) {

	}

	writeGrapheToFile(graph, fileName);

	return RES_OK;
}

// Permet de redicectionner l'utilisateur
int menuRedirect(int userChoice) {

	switch(userChoice) {
		case MENU_CREATION:
			menuCreation();
			menuSecondMenu();
			break;
		case MENU_LECTURE:
			menuLecture();
			menuSecondMenu();
			break;
		case MENU_QUITTER:
			menuQuitter();
			break;
		case MENU_MAIN_MENU:
			menuMainMenu(NULL);
			break;
		case MENU_CREATION_ALEATOIRE:
			menuCreationAleatoire();
			menuSecondMenu();
			break;
		case MENU_INSERTION_SOMMET:
			menuInsertionSommet();
			menuSecondMenu();
			break;
		case MENU_SUPPRESSION_SOMMET:
			menuSuppressionSommet();
			menuSecondMenu();
			break;
		case MENU_INSERTION_ARETE:
			menuInsertionArete();
			menuSecondMenu();
			break;
		case MENU_SUPPRESSION_ARETE:
			menuSuppressionArete();
			menuSecondMenu();
			break;
		case MENU_SAUVEGARDER:
			menuSauvegarder();
			menuSecondMenu();
			break;
		case MENU_SECOND_MENU:
			menuSecondMenu();
			break;
		case MENU_COMPLETE_GRAPH:
			menuCompleterGraph();
			menuSecondMenu();
		break;
		case MENU_EXACT_TSP_SOLUTION:
			menuExactTSPSolution();
			menuSecondMenu();
			break;
		case MENU_PLUS_PROCHE_VOISIN:
			menuPlusProcheVoisin();
			menuSecondMenu();
			break;
		case MENU_PLUS_PETIT_DETOUR:
			menuPlusPetitDetour();
			menuSecondMenu();
			break;
		case MENU_CALCUL_GRAPH_ARPM:
			menuCalculGraphARPM();
			menuSecondMenu();
			break;
		case MENU_CALCUL_CHRISTOFIDES:
			algorithmChristofides(graph);
			menuSecondMenu();
			break;
		case MENU_AFFICHER:
			menuAfficher();
			menuSecondMenu();
			break;
		default:
			break;
	}

	return RES_OK;
}

// Permet d'inserer un sommet dans un graph
void menuInsertionSommet() {

	int numeroDeSommet = 0;
	char c;

	printf("Veuillez saisir le numero de sommet ou \n");
	printf("saisissez -1 pour annuler l'insertion :");

	if (scanf("%d%c", &numeroDeSommet, &c) != 2) {
		printf("Saisie est invalide !\n\n\n");
		menuQuitter();
	}
	else if(numeroDeSommet == -1) {
		menuSecondMenu();
	}
	else if (c != '\n' ) {
		printf("Extraneous input\n\n\n");
		menuQuitter();
	}

	int res = insertionSommet(graph, numeroDeSommet);

	if (res == SOMMET_DEJA_EXISTANT) {
		printf("Attention le sommet %d est existe déjà !\n", numeroDeSommet);
		menuInsertionSommet();
	}

	if (res == SOMMET_INVALIDE) {
		printf("Attention le sommet %d n'est pas valide !\n", numeroDeSommet);
		menuInsertionSommet();
	}
}

// Permet de supprimer un sommet d'un graph
void menuSuppressionSommet() {

	int numeroDeSommet = 0;
	char c;

	printf("Veuillez saisir le numero de sommet ou \n");
	printf("saisissez -1 pour annuler l'insertion :");

	if (scanf("%d%c", &numeroDeSommet, &c) != 2) {
		printf("Saisie est invalide !\n\n\n");
		menuQuitter();
	}
	else if(numeroDeSommet == -1) {
		menuSecondMenu();
	}
	else if (c != '\n' ) {
		printf("Extraneous input\n\n\n");
		menuQuitter();
	}

	int res = suppressionSommet(graph, numeroDeSommet);

	if (res == GRAPHE_INEXISTANT) {
		printf("Attention le graph n'existe pas !\n");
		menuSuppressionSommet();
	}
	else if (res == SOMMET_INVALIDE) {
		printf("Attention le sommet %d n'est pas valide !\n", numeroDeSommet);
		menuSuppressionSommet();
		return;
	}
	else if (res == SOMMET_INEXISTANT) {
		printf("Attention le sommet %d n'existe pas !\n", numeroDeSommet);
		menuSuppressionSommet();
	}
}

// Permet d'inserer une arete dans un graph
void menuInsertionArete() {

	int a = 0, b = 0; 
	double poids = 0.0;
	char c, oriente;

	printf("Veuillez saisir le numero de premier sommet ou \n");
	printf("saisissez -1 pour annuler l'insertion :");

	if (scanf("%d%c", &a, &c) != 2) {
		printf("Saisie est invalide !\n\n\n");
		menuQuitter();
	}
	else if(a == -1) {
		menuSecondMenu();
	}
	else if (c != '\n' ) {
		printf("Extraneous input\n\n\n");
		menuQuitter();
	}

	printf("Veuillez saisir le numero de deuxieme sommet : ");

	if (scanf("%d%c", &b, &c) != 2) {
		printf("Saisie est invalide !\n\n\n");
		menuQuitter();
	}
	else if (c != '\n' ) {
		printf("Extraneous input\n\n\n");
		menuQuitter();
	}

	printf("Veuillez saisir le poids de sommet: ");

	if (scanf("%lf%c", &poids, &c) != 2) {
		printf("Saisie est invalide !\n\n\n");
		menuQuitter();
	}
	else if (c != '\n' ) {
		printf("Extraneous input\n\n\n");
		menuQuitter();
	}

	printf("Veuillez définir si elle est orienté(o) ou non(n): ");

	if (scanf("%c%c", &oriente, &c) != 2) {

	}
	else if (c != '\n' ) {
		printf("Extraneous input\n\n\n");
		menuQuitter();
	}

	int res = insertionArete(graph, a, b, poids, oriente);

	if (res == GRAPHE_INEXISTANT) {
		printf("Attention le graph n'existe pas !\n");
		menuInsertionArete();
	}
	else if (res == SOMMET_INVALIDE) {
		printf("Attention au moins un des sommet est invalide !\n");
		menuInsertionArete();
	}
	else if (res == SOMMET_INEXISTANT) {
		printf("Attention au moins un des sommet n'existe pas!\n");
		menuInsertionArete();
	}
	else if (res == POIDS_INVALIDE) {
		printf("Attention le poids saisie n'est pas valide!\n");
		menuInsertionArete();
	}
}

// Permet de supprimer une arete d'un graph
void menuSuppressionArete() {

	int a = 0, b = 0;
	char c, oriente;

	printf("Veuillez saisir le numero de premier sommet ou \n");
	printf("saisissez -1 pour annuler l'insertion :");

	if (scanf("%d%c", &a, &c) != 2) {
		printf("Saisie est invalide !\n\n\n");
		menuQuitter();
	}
	else if(a == -1) {
			menuSecondMenu();
	}
	else if (c != '\n' ) {
		printf("Extraneous input\n\n\n");
		menuQuitter();
	}

	printf("Veuillez saisir le numero de deuxieme sommet : ");

	if (scanf("%d%c", &b, &c) != 2) {
		printf("Saisie est invalide !\n\n\n");
		menuQuitter();
	}
	else if (c != '\n' ) {
		printf("Extraneous input\n\n\n");
		menuQuitter();
	}

	printf("Veuillez définir si elle est orienté(o) ou non(n): ");

	if (scanf("%c%c", &oriente, &c) != 2) {

	}
	else if (c != '\n' ) {
		printf("Extraneous input\n\n\n");
		menuQuitter();
	}

	int res = suppressionArete(graph, a, b, oriente);

	if (res == GRAPHE_INEXISTANT) {
		printf("Attention le graph n'existe pas !\n");
		menuInsertionArete();
	}
	else if (res == SOMMET_INVALIDE) {
		printf("Attention au moins un des sommet est invalide !\n");
		menuInsertionArete();
	}
	else if (res == SOMMET_INEXISTANT) {
		printf("Attention au moins un des sommet n'existe pas!\n");
		menuInsertionArete();
	}
	else if (res == TYPE_ARETE_INVALID) {
		printf("Attention saise de type d'arete orienté/non n'est pas valide!\n");
		menuInsertionArete();
	}
}

// Affiche le graph
void menuAfficher() {
	affichageGraphe(graph);
}

// Libere tout le mémoire utilisé
int menuFreeAllMemory() {

	if (graph != NULL) {
		freeGraphe(&graph);
		graph = NULL;
	}

	return RES_OK;
}


int menuCreationAleatoire() {

	userChoice = -1;
	menuFreeAllMemory();

	printf("\nVeuillez saisir le nombre maximum de sommet : ");

	char c;

	if (scanf("%d%c", &userChoice, &c) != 2) {
		printf("Saisie est invalide !\n");
		menuRedirect(MENU_MAIN_MENU);
		return RES_OK;
	}
	else if(userChoice <= 0) {
		printf("Saisie est negative ou null\n" );
	}
	else if (c != '\n' ) {
		printf("Extraneous input\n");
	}


	printf("\nVeuillez saisir la graine : ");

	int graine;

	if (scanf("%d%c", &graine, &c) != 2) {
		printf("Saisie est invalide !\n");
		menuRedirect(MENU_MAIN_MENU);
		return RES_OK;
	}
	else if(graine <= 0) {
		printf("Saisie est negative ou null\n" );
	}
	else if (c != '\n' ) {
		printf("Extraneous input\n");
	}

	// Création de graph
	int res = createGraph(&graph, userChoice, graine);

	// Invalide max sommet
	if (res != RES_OK) {
		printf("\nProblem occurred while calling createGraph "
				"- code : %d!\n", res);
		menuRedirect(MENU_MAIN_MENU);
	}
	else {
		menuSecondMenu();
//		menuFreeAllMemory();
	}

	return RES_OK;
}


// Call to complete the graph
int menuCompleterGraph() {

	// To save (x, y) chosen randomly
	int *ligne = NULL, *col = NULL;

	int size = graph->nbMaxSommets;

	// Memory allocation
	ligne = (int *) malloc (sizeof(int) * size);
	col = (int *) malloc (sizeof(int) * size);

	// Allocating verification
	if (ligne == NULL || col == NULL) {
		printf("Attention, memory problem on malloc - createGraph\n");
		return PROBLEME_MEMOIRE;
	}

	printf("\nVeuillez saisir la graine : ");

	int graine;
	char c;

	if (scanf("%d%c", &graine, &c) != 2) {
		printf("Saisie est invalide !\n");
		menuRedirect(MENU_MAIN_MENU);
		return RES_OK;
	}
	else if(graine <= 0) {
		printf("Saisie est negative ou null\n" );
	}
	else if (c != '\n' ) {
		printf("Extraneous input\n");
	}

	// Let's get generated coordinates
	int res = generateCoordonne(&ligne, &col, size, graine);


	// Create all vertex needed from 0 to SIZE
	res = insertAllVertex(graph);

	// In case of memory problem
	if (res == PROBLEME_MEMOIRE) {
		printf("Attention, memory problem acquired - createGraph\n");
		free(ligne); free(col);
		return PROBLEME_MEMOIRE;
	}

	// Complete graph, each vertex is connected with another one
	completeGraph(graph, ligne, col);

	// Don't need any more
	free(ligne);
	free(col);

	return RES_OK;
}


int menuExactTSPSolution() {

	clock_t start = clock();

	getExactTSPSolution(graph);

	printf("Time elapsed: %f\n", ((double)clock() - start) / CLOCKS_PER_SEC);

	return RES_OK;
}

int menuPlusProcheVoisin() {

	int i;
	int root = 1;
	int* tab = NULL ;
	tab = (int *) malloc (sizeof(int) * graph->nbMaxSommets);

	for (i = 0; i < graph->nbMaxSommets; ++i) {
		tab[i] = - 1;
	}

	printf("\nResultat de l'heuristique du plus proche voisin\n\n");
	nearestNeighbor(graph, root, &tab);

	for (i = 0; i < graph->nbMaxSommets; i++) {		
			printf("%d ",tab[i]+1);		
	}
	printf("%d\n", root);
	printf("the cycle length : %f\n", getPathSize(graph, tab));	
	printf("\n");
	free(tab);

	return RES_OK;
}


int menuPlusPetitDetour() {

	int i;
	int root = 1;
	int* tab = NULL ;
	tab = (int *) malloc (sizeof(int) * graph->nbMaxSommets);

	for (i = 0; i < graph->nbMaxSommets; ++i) {
		tab[i] = - 1;
	}

	printf("\nResultat de l'heuristique du plus petit detour\n\n");

	smallestDetour(graph,root,2,3,&tab);

	for (i = 0; i < graph->nbMaxSommets; i++) {		
			if (tab[i] != -1)			
				printf("%d ",tab[i]+1);			
			else{
				printf("Nombre de max sommets doit etre superieur ou egale a 3\n");
				return MAX_SOMMET_INVALIDE;
			}
	}
	printf("%d\n", root);
	printf("the cycle length : %f\n", getPathSize(graph, tab));	
	printf("\n");
	free(tab);

	return RES_OK;
}

int menuCalculGraphARPM() {

	if (graph == NULL) {
		printf("\nGraph is null");
		return GRAPHE_INEXISTANT;
	}
	int root = 1;

	less2Factor(graph, root);
	printf("%d\n",root);

	return RES_OK;
}
